package com.caseProject.puremvc.model.business
{
	import com.caseProject.puremvc.model.Diagram;
	import com.caseProject.puremvc.model.DiagramNames;
	import com.caseProject.puremvc.model.events.FileManagerEvent;
	import com.caseProject.puremvc.model.vo.DiagramActivityVO;
	import com.caseProject.puremvc.model.vo.DiagramStateVO;
	import com.caseProject.puremvc.model.vo.ElementVO;
	import com.caseProject.puremvc.model.vo.PartitionVO;
	import com.caseProject.puremvc.model.vo.TransitionVO;
	
	import flash.events.Event;
	import flash.events.EventDispatcher;
	import flash.filesystem.File;
	import flash.filesystem.FileMode;
	import flash.filesystem.FileStream;
	import flash.net.FileFilter;

	public class FileManager extends EventDispatcher
	{
		private static var instance:FileManager;
		
		private var xmlProject:XML;
		private var tag:String;
		
		private var file:File;
		private var filestream:FileStream;
		
		private var diagramList:Vector.<Diagram>;
		
		private var filter:FileFilter;
		
		public static function getInstance():FileManager
		{
			if (instance == null)
			{
				instance = new FileManager();
			}
			return instance as FileManager;
		}
		
		public function FileManager()
		{
			this.filter = new FileFilter ("XML,TXT", "*.xml;*.txt");
			this.diagramList = new Vector.<Diagram>();
			this.filestream = new FileStream();
			this.tag = '<project>\n\t<stateDiagrams>\n\t</stateDiagrams>\n\t<activityDiagrams>\n\t</activityDiagrams>\n</project>';
		}
		
		public function resetDiagramList():void
		{
			this.diagramList = new Vector.<Diagram>();
		}
		
		/**
		 * Creates a new XML file to save the project
		 * */
		public function createFile ():void
		{
			this.xmlProject = new XML(this.tag);
			
			this.diagramList = new Vector.<Diagram>();
			this.file = new File();
			file.save(this.xmlProject, "Projeto.txt");
		}
		
		/**
		 * Open browser for xml 
		 * */
		public function openFile():void
		{
			this.diagramList = new Vector.<Diagram>;
			var file:File = new File();
			file.browseForOpen("Abrir Projeto", [this.filter]);
			file.addEventListener(Event.SELECT, onSelectFile);			
		}
		
		protected function onSelectFile(event:Event):void
		{
			this.loadFile(File (event.target).nativePath);
		}		
		
		public function loadFile(url:String):void
		{
			this.file = new File (url);
			filestream.open(this.file, FileMode.READ);
			this.xmlProject = new XML(filestream.readUTFBytes(this.file.size));
			filestream.close();
			
			this.getStateDiagramFromXML();
			this.getActivityDiagramFromXML();
			
			this.dispatchEvent(new FileManagerEvent(FileManagerEvent.LOAD_DATA_SUCCESS, this.diagramList));
		}
		
		private function getStateDiagramFromXML():void
		{
			for each (var state:XML in this.xmlProject.stateDiagrams.state) 
			{	
				var stateDiagram:DiagramStateVO = new DiagramStateVO();
				var elementsList:Vector.<ElementVO> = new Vector.<ElementVO>();
				var transitionsList:Vector.<TransitionVO> = new Vector.<TransitionVO>();
				
				if (state != null)
				{
					stateDiagram.id = int(state.@id);
					stateDiagram.name = state.@name;
					
					if (this.getElementVOFromXML(state.elements.element))
					{
						elementsList = this.getElementVOFromXML(state.elements.element);
					}
					
					if (this.getTransitionVOFromXML(state.transitions.transition))
					{
						transitionsList = this.getTransitionVOFromXML(state.transitions.transition);
					}
					
					stateDiagram.addElements(elementsList);
					stateDiagram.addTransitions(transitionsList);
					
					this.diagramList.push(stateDiagram);
				}
			}
		}
		
		private function getActivityDiagramFromXML():void
		{			
			for each (var activity:XML in this.xmlProject.activityDiagrams.activity) 
			{	
				var activityDiagram:DiagramActivityVO = new DiagramActivityVO();
				var elementsList:Vector.<ElementVO> = new Vector.<ElementVO>();
				var transitionsList:Vector.<TransitionVO> = new Vector.<TransitionVO>();
				var partitionList:Vector.<PartitionVO> = new Vector.<PartitionVO>();
				
				if (activity != null)
				{
					activityDiagram.id = int(activity.@id);
					activityDiagram.name = activity.@name;
					
					if (this.getElementVOFromXML(activity.elements.element))
					{
						elementsList = this.getElementVOFromXML(activity.elements.element);
					}
					
					if (this.getTransitionVOFromXML(activity.transitions.transition))
					{
						transitionsList = this.getTransitionVOFromXML(activity.transitions.transition);
					}
					
					if (this.getPartitionVOFromXML(activity.partitions.partition))
					{
						partitionList = this.getPartitionVOFromXML(activity.partitions.partition);
					}
					
					activityDiagram.addElements(elementsList);
					activityDiagram.addTransitions(transitionsList);
					activityDiagram.addPartitions(partitionList);
					
					this.diagramList.push(activityDiagram);
				}
			}
		}
		
		private function getElementVOFromXML (path:XMLList):Vector.<ElementVO>
		{
			var list:Vector.<ElementVO> = new Vector.<ElementVO>();
			
			for each (var element:XML in path) 
			{
				var elementVO:ElementVO = new ElementVO();
				
				elementVO.doWhile = element.@doWhile;
				elementVO.entry = element.@entry;
				elementVO.exit = element.@exit;
				elementVO.id = int(element.@id);
				elementVO.name = element.@name;
				elementVO.posX = Number(element.@posX);
				elementVO.posY = Number(element.@posY);
				elementVO.type = element.@type;
				elementVO.heightValue = element.@heightValue;
				elementVO.widthValue = element.@widthValue;
				
				list.push(elementVO);
			}			
			return list;
		}
		
		private function getTransitionVOFromXML (path:XMLList):Vector.<TransitionVO>
		{
			var list:Vector.<TransitionVO> = new Vector.<TransitionVO>();
			
			for each (var transition:XML in path) 
			{
				var transitionVO:TransitionVO = new TransitionVO();
				
				transitionVO.action = transition.@action;
				transitionVO.elementFromId = int(transition.@elementFromId);
				transitionVO.elementToId = int(transition.@elementToId);
				transitionVO.event = transition.@event;
				transitionVO.guard = transition.@guard;
				transitionVO.id = int(transition.@id);
				
				list.push(transitionVO);
			}			
			return list;
		}
		
		private function getPartitionVOFromXML (path:XMLList):Vector.<PartitionVO>
		{
			var list:Vector.<PartitionVO> = new Vector.<PartitionVO>();
			
			for each (var partition:XML in path) 
			{
				var partitionVO:PartitionVO = new PartitionVO();
				
				partitionVO.id = int(partition.@id);
				partitionVO.posX = Number(partition.@posX);
				partitionVO.posY = Number(partition.@posY);
				
				partitionVO.addElements(this.getElementVOFromXML(path.element));
				
				list.push(partitionVO);
			}			
			return list;
		}
		
		/**
		 * Saves the diagrams updates on the open XML project file 
		 * */
		public function saveFile(list:Vector.<Diagram>):void
		{
			this.xmlProject = new XML(this.tag);
			
			for (var i:int = 0; i<list.length; i++) {
				var voNode:XML;
				
				switch (list[i].type){
					case DiagramNames.STATE:
						voNode = new XML(DiagramStateVO (list[i]).toString());
						XMLList (this.xmlProject.stateDiagrams).appendChild(voNode);
						break;
					
					case DiagramNames.ACTIVITY:
						voNode = new XML(DiagramActivityVO(list[i]).toString());
						XMLList (this.xmlProject.activityDiagrams).appendChild(voNode);
						break;
					
					default:
						throw new Error ("FileManager: Diagram Type Not Found");
				}
			}
			
			filestream.open(this.file, FileMode.WRITE);
			filestream.writeUTFBytes(this.xmlProject);
			filestream.close();
		}
	}
}